home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / netconf / ipalias.c < prev    next >
C/C++ Source or Header  |  1996-06-22  |  10KB  |  431 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <ctype.h>
  5. #include <sys/socket.h>
  6. #include <netdb.h>
  7. #include "netconf.h"
  8. #include "../userconf/userconf.h"
  9. #include "internal.h"
  10. #include "../misc/misc.h"
  11. #include "../paths.h"
  12. #include "netconf.m"
  13.  
  14. static NETCONF_HELP_FILE help_aliases ("ip_aliases");
  15. static CONFIG_FILE f_aliases (PROC_NET_ALIASES
  16.     ,help_aliases
  17.     ,CONFIGF_OPTIONNAL|CONFIGF_PROBED);
  18. static CONFIG_FILE f_alias_types (PROC_NET_ALIAS_TYPES
  19.     ,help_aliases
  20.     ,CONFIGF_OPTIONNAL|CONFIGF_PROBED);
  21.  
  22.  
  23. /* #Specification: netconf / aliases / strategy
  24.     linuxconf will automaticly manage/assign/remove all ip_alias based
  25.     on the definitions it received. It will select by itself the
  26.     alias number (ethx:NUMBER) by monitoring the currently allocated
  27.     ones.
  28. */
  29.  
  30. PUBLIC IP_ALIAS::IP_ALIAS(int _num, const char *_ip)
  31. {
  32.     num = _num;
  33.     ip.setfrom (_ip);
  34. }
  35.  
  36. PUBLIC IP_ALIAS::IP_ALIAS(const char *_ip)
  37. {
  38.     num = -1;    // Not yet setup in the kernel
  39.     ip.setfrom (_ip);
  40. }
  41.  
  42.  
  43. PUBLIC int IP_ALIAS::unset (const char *devname)
  44. {
  45.     char cmd[100];
  46.     sprintf (cmd,"%s:%d- 0.0.0.0",devname,num);
  47.     return netconf_system_if ("ifconfig",cmd);
  48. }
  49.  
  50. PUBLIC int IP_ALIAS::set (int _num, const char *devname)
  51. {
  52.     char cmd[100];
  53.     sprintf (cmd,"%s:%d %s",devname,_num,ip.get());
  54.     int ret = netconf_system_if ("ifconfig",cmd);
  55.     if (ret == 0){
  56.         sprintf (cmd,"add %s %s:%d",ip.get(),devname,_num);
  57.         ret = netconf_system_if ("route",cmd);
  58.     }
  59.     return ret;
  60. }
  61.  
  62.  
  63. PUBLIC IP_ALIAS *IP_ALIASES::getitem(int no)
  64. {
  65.     return (IP_ALIAS*)ARRAY::getitem(no);
  66. }
  67.  
  68. /*
  69.     Locate one alias from its IP number
  70. */
  71. PUBLIC IP_ALIAS *IP_ALIASES::getitem(const char *ip)
  72. {
  73.     IP_ALIAS *ret = NULL;
  74.     int n = getnb();
  75.     for (int i=0; i<n; i++){
  76.         IP_ALIAS *a = getitem(i);
  77.         if (a->ip.cmp(ip)==0){
  78.             ret = a;
  79.             break;
  80.         }
  81.     }
  82.     return ret;
  83. }
  84.  
  85. /*
  86.     Read the aliases currently configured for a device (eth0 for example)
  87. */
  88. PUBLIC void IP_ALIASES::readproc (const char *devname)
  89. {
  90.     FILE *fin = f_aliases.fopen ("r");
  91.     if (fin != NULL){
  92.         char buf[300];
  93.         int len = strlen(devname);
  94.         while (fgets(buf,sizeof(buf)-1,fin)!=NULL){
  95.             if (strncmp(buf,devname,len)==0
  96.                 && buf[len] == ':'){
  97.                 int id;
  98.                 int family;
  99.                 char ip[100];
  100.                 sscanf (buf+len+1,"%d %d %s",&id,&family,ip);
  101.                 /* #Specification: netconf / aliases / 0.0.0.0
  102.                     The file /proc/net/aliases contains entries
  103.                     with an IP number of 0.0.0.0. Theses entries
  104.                     are "downed" interface. I suspect they should be
  105.                     left out of the table. Anyway, they are ignored
  106.                     by linuxconf.
  107.                 */
  108.                 if (strcmp(ip,"0.0.0.0")!=0){
  109.                     add (new IP_ALIAS(id,ip));
  110.                 }
  111.             }
  112.         }
  113.         fclose (fin);
  114.     }
  115. }
  116.  
  117. /*
  118.     Return the number of the last allocated alias numer (ethx:N)
  119. */
  120. PUBLIC int IP_ALIASES::getmaxnum()
  121. {
  122.     int ret = 0;
  123.     int n = getnb();
  124.     for (int i=0; i<n; i++){
  125.         IP_ALIAS *a = getitem(i);
  126.         if (a->num > ret) ret = a->num;
  127.     }
  128.     return ret;
  129. }
  130.  
  131. /*
  132.     Translate a IP number into up to four numbers.
  133.     Return the number of numbers written into tbi.
  134. */
  135. static int ipalias_evalip (const char *str, int tbi[4])
  136. {
  137.     int nb = 0;
  138.     while (*str != '\0'){
  139.         tbi[nb++] = atoi(str);
  140.         str = str_skipdig (str);
  141.         if (*str == '.') str++;
  142.     }
  143.     return nb;
  144. }
  145.  
  146. /*
  147.     Record the aliases definition.
  148.     The function setup has to be called after setting all the definition
  149. */
  150. PUBLIC int IP_ALIASES::setnew (
  151.     const char *devip,    // Ip number of the device
  152.     const char *ips,    // A bunch of IP alias to allocate
  153.     char *err)            // Collect error messages
  154. {
  155.     /* #Specification: netconf / aliases / defining many
  156.         The user interface of linuxconf allows you to define several
  157.         IP aliases for a device. These aliases are generally used for
  158.         virtual host httpd server. Many installation will required a fair
  159.         amount of IP number, one for each domain they serve. To help setup
  160.         those aliases, linuxconf do support different syntax.
  161.  
  162.         #
  163.         -You can define menu IP number on a single line.
  164.         -You can define a range of IP number like this x.y.z.a-b. This
  165.          will effectivly define one alias per number from a to b.
  166.         -You can define an alias just by specifying the suffix of the
  167.          ip number. For example, an ethernet device (eth0) may have the IP
  168.          192.168.1.1. By defining the alias 2 3 4 5, you are effectivly
  169.          defining:
  170.  
  171.                 eth0:1    192.168.1.2
  172.                 eth0:2    192.168.1.3
  173.                 eth0:3    192.168.1.4
  174.                 eth0:4    192.168.1.5
  175.         -The abreviated syntax define in the previous paragraph also work
  176.          with ranges. The previous example could be written 2-5.
  177.         -You can use names (fqdn) to setup aliases.
  178.         #
  179.     */
  180.  
  181.     int ret = 0;
  182.     while (1){
  183.         ips = str_skip(ips);
  184.         if (*ips == '\0') break;
  185.         char word[200];
  186.         ips = str_copyword (word,ips);
  187.         if (isdigit (word[0])){
  188.             char *pt = strchr(word,'-');
  189.             int start=0,end=0;
  190.             if (pt != NULL){
  191.                 *pt++ = '\0';
  192.                 end = atoi(pt);
  193.             }
  194.             char *first = strrchr(word,'.');
  195.             if (first != NULL){
  196.                 *first++ = '\0';
  197.                 start = atoi(first);
  198.             }else{
  199.                 start = atoi(word);
  200.                 word[0] = '\0';
  201.             }
  202.             if (end < start) end = start;
  203.             int tbdev[4];
  204.             ipalias_evalip(devip,tbdev);
  205.             int tbspec[4];
  206.             int nbspec = ipalias_evalip(word,tbspec);
  207.             memcpy (tbdev+(3-nbspec),tbspec,nbspec*sizeof(int));
  208.             for (int i=start; i<=end; i++){
  209.                 sprintf (word,"%d.%d.%d.%d",tbdev[0],tbdev[1],tbdev[2],i);
  210.                 add (new IP_ALIAS (word));
  211.             }
  212.         }else{
  213.             struct hostent *ent = gethostbyname(word);
  214.             if (ent != NULL){
  215.                 devices_ip2a (ent,word);
  216.                 add (new IP_ALIAS(word));
  217.             }else{
  218.                 strcat (err,MSG_U(E_UNKHOST,"Unknown host name "));
  219.                 strcat (err,word);
  220.                 strcat (err,"\n");
  221.                 ret = -1;
  222.             }
  223.         }
  224.     }
  225.     return ret;
  226. }
  227.  
  228. static int ipalias_available()
  229. {
  230.     int ret = 0;
  231.     FILE *fin = f_alias_types.fopen("r");
  232.     if (fin == NULL){
  233.         xconf_error (MSG_U(E_NOALIAS,"No kernel support for devices aliasing"));
  234.     }else{
  235.         char buf[300];
  236.         if (fgets(buf,sizeof(buf)-1,fin)!=NULL){
  237.             while (fgets(buf,sizeof(buf)-1,fin)!=NULL){
  238.                 int id = atoi(buf);
  239.                 if (id == AF_INET){
  240.                     ret = 1;
  241.                     break;
  242.                 }
  243.             }
  244.         }
  245.         fclose (fin);
  246.         if (!ret){
  247.             ret = netconf_system_if ("modprobe","ip_alias") == 0;
  248.         }
  249.     }
  250.     return ret;
  251. }
  252.  
  253. /*
  254.     Install the proper aliases in the kernel.
  255.     Cleanup the one which are not needed anymore.
  256.  
  257.     Return -1 if any errors.
  258. */
  259. PUBLIC int IP_ALIASES::setup (const char *devname)
  260. {
  261.     IP_ALIASES proc;
  262.     proc.readproc(devname);
  263.     int maxnum = proc.getmaxnum();
  264.     int n = getnb();
  265.     int len = maxnum+n+1;
  266.     char lookup[len];
  267.     memset (lookup,0,sizeof(char)*len);
  268.     IP_ALIASES toadd;    // Will contain the items that must be added
  269.     toadd.neverdelete();
  270.     int i;
  271.     for (i=0; i<n; i++){
  272.         IP_ALIAS *a = getitem(i);
  273.         IP_ALIAS *ap = proc.getitem(a->ip.get());
  274.         if (ap != NULL){
  275.             // Alias is already installed
  276.             lookup[ap->num] = 1;
  277.         }else{
  278.             toadd.add(a);
  279.         }
  280.     }
  281.     int ret = 0;
  282.     n = proc.getnb();
  283.     for (i=0; i<n; i++){
  284.         IP_ALIAS *a = proc.getitem(i);
  285.         IP_ALIAS *ap = getitem(a->ip.get());
  286.         if (ap == NULL){
  287.             // Alias is already installed and must be removed
  288.             ret |= a->unset (devname);
  289.         }
  290.     }
  291.     n = toadd.getnb();
  292.     if (n > 0){
  293.         if (ipalias_available()){
  294.             int allocnum = 0;
  295.             for (i=0; i<n; i++){
  296.                 IP_ALIAS *a = toadd.getitem(i);
  297.                 while (lookup[allocnum] != 0) allocnum++;
  298.                 ret |= a->set (allocnum,devname);
  299.                 allocnum++;
  300.             }
  301.         }else{
  302.             ret = -1;
  303.         }
  304.     }
  305.     return ret;
  306. }
  307.  
  308. static char IPALIAS[]="ipalias";
  309.  
  310. int alias_setup(const char *devname)
  311. {
  312.     int ret = -1;
  313.     IFCONFIG_INFO info;
  314.     if (ifconfig_getinfo(devname,info)!=-1){
  315.         IP_ALIASES alias;
  316.         SSTRINGS strs;
  317.         linuxconf_getall (IPALIAS,devname,strs,0);
  318.         ret = 0;
  319.         char err[10000];
  320.         err[0] = '\0';
  321.         for (int i=0; i<strs.getnb(); i++){
  322.             SSTRING *s = strs.getitem(i);
  323.             ret |= alias.setnew (info.ip_addr,s->get(),err);
  324.         }
  325.         if (ret == 0){
  326.             ret = alias.setup(devname);
  327.         }else if (err[0] != '\0'){
  328.             xconf_error (MSG_U(E_SETALIAS
  329.                  ,"Invalid alias setup for device %s\n%s")
  330.                 ,devname,err);
  331.         }
  332.     }
  333.     return ret;
  334. }
  335.  
  336. /*
  337.     Install the aliases for all devices
  338. */
  339. int alias_setup ()
  340. {
  341.     int ret = -1;
  342.     SSTRINGS list;
  343.     if (devlist_read (list) != -1){
  344.         int n = list.getnb();
  345.         ret = 0;
  346.         for (int i=0; i<n; i++){
  347.             SSTRING *s = list.getitem(i);
  348.             ret |= alias_setup (s->get());
  349.         }
  350.     }
  351.     return ret;
  352. }
  353.  
  354. static void alias_edit(const char *devname)
  355. {
  356.     SSTRINGS lst;
  357.     linuxconf_getall (IPALIAS,devname,lst,1);
  358.     int i;
  359.     for (i=0; i<10; i++) lst.add(new SSTRING);
  360.     int nof = 0;
  361.     while (1){
  362.         DIALOG dia;
  363.         for (i=0; i<lst.getnb(); i++){
  364.             dia.newf_str (i==0 ? MSG_U(F_IPALIASES,"IP aliases") : ""
  365.                 ,*lst.getitem(i));
  366.         }
  367.         char buf[100];
  368.         sprintf (buf,MSG_U(T_IPALIASFORDEV,"IP aliases for device %s")
  369.             ,devname);
  370.         MENU_STATUS code = dia.edit (buf
  371.             ,MSG_U(I_IPALIASFORDEV
  372.              ,"You can enter alternative IP numbers for a\n"
  373.               "network interface. You can enter several numbers\n"
  374.               "per lines. Many time savers syntax are supported\n"
  375.               "Here are some examples for:\n"
  376.               "    192.168.1.10 192.168.1.11 192.168.1.12\n"
  377.               "    192.168.1.10-12\n"
  378.               "    10-12")
  379.             ,help_aliases
  380.             ,nof);
  381.         if (code == MENU_CANCEL || code == MENU_ESCAPE){
  382.             break;
  383.         }else if (code == MENU_ACCEPT){
  384.             if (perm_rootaccess(MSG_U(P_UPDALIAS,"to update IP aliases"))){
  385.                 for (i=0; i<lst.getnb(); i++){
  386.                     SSTRING *s = lst.getitem(i);
  387.                     if (s->is_empty()){
  388.                         lst.remove_del (s);
  389.                         i--;
  390.                     }
  391.                 }
  392.                 linuxconf_replace (IPALIAS,devname,lst);
  393.                 linuxconf_save();
  394.                 break;
  395.             }
  396.         }
  397.     }
  398. }
  399.  
  400. void alias_edit()
  401. {
  402.     SSTRINGS lst;
  403.     if (devlist_read(lst)!=-1){
  404.         int sel = 0;
  405.         while (1){
  406.             DIALOG dia;
  407.             int n = lst.getnb();
  408.             lst.sort();
  409.             for (int i=0; i<n; i++){
  410.                 dia.new_menuitem ("",lst.getitem(i)->get());
  411.             }
  412.             MENU_STATUS code = dia.editmenu (
  413.                  MSG_U(T_IPALIASES,"Edit IP aliases configurations")
  414.                 ,MSG_U(I_SYSTEMS,"Each network device may have several\n"
  415.                  "IP number. Alternate ones are called alias and are\n"
  416.                  "entered here.\n")
  417.                 ,help_aliases
  418.                 ,sel,0);
  419.             if (code == MENU_OK){
  420.                 if (n > 0){
  421.                     SSTRING *s = lst.getitem(sel);
  422.                     alias_edit (s->get());
  423.                 }
  424.             }else if (code == MENU_ESCAPE || code == MENU_QUIT){
  425.                 break;
  426.             }
  427.         }
  428.     }
  429. }
  430.  
  431.